import { useEffect, createContext, useContext, useReducer } from 'react';

const BASE_URL = 'http://localhost:8000';

// 1. 创建一个新的 context
const CitiesContext = createContext();

const initialState = {
  cities: [],
  isLoading: false,
  currentCity: {},
  error: ''
};

function reducer(state, action) {
  switch (action.type) {
    case 'loading':
      return {
        ...state,
        isLoading: true
      };
    case 'rejected':
      return {
        ...state,
        isLoading: false,
        error: action.payload
      };
    case 'cities/loaded':
      return {
        ...state,
        cities: action.payload,
        isLoading: false
      };
    case 'city/loaded':
      return {
        ...state,
        currentCity: action.payload,
        isLoading: false
      };
    case 'cities/created':
      return {
        ...state,
        cities: [...state.cities, action.payload],
        currentCity: action.payload,
        isLoading: false
      };
    case 'cities/deleted':
      return {
        ...state,
        cities: state.cities.filter((city) => city.id !== action.payload),
        currentCity: {},
        isLoading: false
      };
    case 'city/selected':
      return {
        ...state,
        currentCity: action.payload,
        isLoading: false
      };
    default:
      throw new Error('Unknown action type');
  }
}

// 2. 创建一个 context provider
const CitiesProvider = ({ children }) => {
  const [{ cities, isLoading, currentCity, error }, dispatch] = useReducer(
    reducer,
    initialState
  );

  useEffect(() => {
    async function fetchCities() {
      try {
        dispatch({ type: 'loading' });

        const response = await fetch(`${BASE_URL}/cities`);
        const data = await response.json();

        dispatch({ type: 'cities/loaded', payload: data });
      } catch (err) {
        dispatch({ type: 'rejected', payload: err.message });
      }
    }

    fetchCities();
  }, []);

  async function getCity(id) {
    if (Number(id) === currentCity.id) return;

    try {
      dispatch({ type: 'loading' });

      const response = await fetch(`${BASE_URL}/cities/${id}`);
      const data = await response.json();

      dispatch({ type: 'city/loaded', payload: data });
    } catch (err) {
      dispatch({ type: 'rejected', payload: err.message });
    }
  }

  async function createCity(newCity) {
    try {
      dispatch({ type: 'loading' });

      const response = await fetch(`${BASE_URL}/cities`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(newCity)
      });
      const data = await response.json();

      dispatch({ type: 'cities/created', payload: data });
    } catch (err) {
      dispatch({ type: 'rejected', payload: err.message });
    }
  }

  async function deleteCity(id) {
    try {
      dispatch({ type: 'loading' });

      await fetch(`${BASE_URL}/cities/${id}`, {
        method: 'DELETE'
      });

      dispatch({ type: 'cities/deleted', payload: id });
    } catch (err) {
      dispatch({ type: 'rejected', payload: err.message });
    }
  }

  return (
    <CitiesContext.Provider
      value={{
        cities,
        isLoading,
        currentCity,
        getCity,
        createCity,
        deleteCity,
        error
      }}
    >
      {children}
    </CitiesContext.Provider>
  );
};

function useCities() {
  const ctx = useContext(CitiesContext);
  if (ctx === undefined) {
    throw new Error('CitiesContext was used outside of the CitiesProvider');
  }
  return useContext(CitiesContext);
}

export { CitiesProvider, useCities };
